package parser;


/*
 * Parser for Mark
 * Takes in command from GUI.Main, and call appropriate method in mark
 * 
 */


import java.util.ArrayList;
import java.util.PriorityQueue;

import storage.Storage;
import logger.Logger;
import logic.Display;
import logic.Find;
import logic.History;
import logic.Mark;
import memory.GenericEvents;
import memory.Memory;

public class ParserMark extends ParserMain {

	private static final String EMPTY_STRING = "";
	private static final int INVALID = -1;
	private static final String SPACE = " ";
	private static final String ERROR_ITEM_NOT_FOUND = "Item not found: ";
	private static final String ERROR_MULTIPLE_ITEMS_WITH_IDENTICAL_NAME_FOUND = "Multiple items with identical name found";
	private static final String ERROR_MARK_ONLY_INTEGER = "When in listview, please mark items using their number index only";
	private static final String ERROR_MARK_ONLY_IN_LISTVIEW = "You may only mark in listview or with item in full display.";
	private static final String ERROR_ONLY_MARK_ITEM_IN_DISPLAY = "Please mark single item only in detailed view.";

	private static final int MARK_USING_TASKNAME = 2;
	private static final int MARK_IN_LISTVIEW = 1;
	private static final int MARK_IN_DETAILED = 0;

	//@author A0085082E
	/*
	 * Initialising variables
	 */
	private static void initVar(){
		setType(INVALID);
	}

	//@author A0085082E
	/*
	 * Run mark as called by GUI.Main
	 */
	public static void run(String command, Memory memory){
		initVar();
		setCommand(command);
		runMark(memory);
	}

	//@author A0085082E
	/*
	 * Takes in memory
	 * Set command type and call method corresponding to the command.
	 * If command is invalid, generate error message.
	 * 
	 */
	protected static void runMark(Memory memory){

		setMarkType();
		runCodeIfCommandIsValid(memory);

	}

	//@author A0085082E
	/*
	 * Check if command is valid
	 * If command is invalid, generate error message.
	 * If command is valid, run display
	 */
	private static void runCodeIfCommandIsValid(Memory memory) {
		switch(type){
		case MARK_IN_DETAILED:
			setMarkInDetailed(memory);
			break;
		case MARK_IN_LISTVIEW:
			setMarkInListView(memory);
			break;
		case MARK_USING_TASKNAME:
			setMarkUsingTaskName(memory);
			break;

		default: 
			generalError();
		}
	}

	//@author A0085082E
	/*
	 * Set command type
	 */
	private static void setMarkType(){

		if(command.equals(EMPTY_STRING)){
			setType(MARK_IN_DETAILED);
		}else if(removeAllInt(command).length() == 0){
			setType(MARK_IN_LISTVIEW);
		}else{
			setType(MARK_USING_TASKNAME);
		}

	}

	//@author A0085082E
	/*
	 * Takes in memory
	 * Calls markItemsInDisplay if user is in detailedView
	 * Else print error message
	 * 
	 */
	private static void setMarkInDetailed(Memory memory){
		if (Display.detailedView != null) { // item view
			Mark.markItemsInDisplay();
			updateHistoryAndStorage(memory);
		} else{
			assert Display.detailedView == null;
			System.out.println(ERROR_ONLY_MARK_ITEM_IN_DISPLAY);
			Logger.add(LOGGER_ERROR + ERROR_ONLY_MARK_ITEM_IN_DISPLAY);
		}
	}

	//@author A0085082E
	/*
	 * Takes in memory
	 * Calls markItemsInListView, update history and storage
	 * Print error message if user is not in list view
	 * Or if user input is not all number
	 * 
	 */
	private static void setMarkInListView(Memory memory) {
		if (Display.listView == null) {
			System.out.println(ERROR_MARK_ONLY_IN_LISTVIEW);
			Logger.add(LOGGER_ERROR + ERROR_MARK_ONLY_IN_LISTVIEW);
		}else if(!isIndexOnly()){
			System.out.println(ERROR_MARK_ONLY_INTEGER);
			Logger.add(LOGGER_ERROR + ERROR_MARK_ONLY_INTEGER);
		}else{
			markItemInListView(memory);

		}
	}

	//@author A0085082E
	/*
	 * Remove index that are duplicated and out of bound
	 * Mark items in list view
	 * Update history and storage
	 */
	private static void markItemInListView(Memory memory) {
		String[] rawIndex = command.split(SPACE);
		PriorityQueue<Integer> queue = removeDuplicateAndOutOfBound(rawIndex);
		Mark.markItemsInListView(queue);
		updateHistoryAndStorage(memory);
	}

	//@author A0096677H
	/*
	 * Takes in memory
	 * Calls markDirectly if only one item is found and update history and storage
	 * Print error message if many items with same name are found
	 * or if item is not found
	 * 
	 */
	private static void setMarkUsingTaskName(Memory memory){

		ArrayList<GenericEvents> searchResult = Find.searchExact(command, memory);
		if (searchResult.size() == 1){
			Mark.markDirectly(searchResult.get(0));
			updateHistoryAndStorage(memory);
		} else if (searchResult.size() > 1) {
			Display.displayList(searchResult, ERROR_MULTIPLE_ITEMS_WITH_IDENTICAL_NAME_FOUND);
			Logger.add(LOGGER_ERROR + ERROR_MULTIPLE_ITEMS_WITH_IDENTICAL_NAME_FOUND);
		}else {
			System.out.println(ERROR_ITEM_NOT_FOUND+ command);
			Logger.add(LOGGER_ERROR + ERROR_ITEM_NOT_FOUND+ command);
		}

	}

	//@author A0085082E
	/*
	 * Checks that command contain only number
	 * return true if string command is empty or it only contains number
	 */
	private static Boolean isIndexOnly(){
		return (removeAllInt(command).length() == 0);
	}

	//@author A0085082E
	/*
	 * Update history and storage
	 */
	private static void updateHistoryAndStorage(Memory memory){
		History.advance(memory);
		Storage.saveToStorage(memory);
	}
}
